package cn.tang.tframe.sdm.aop;

import cn.tang.tframe.common.base.BaseResult;
import cn.tang.tframe.common.exception.BaseRtmException;
import cn.tang.tframe.common.utils.ToStringUtil;
import cn.tang.tframe.common.utils.lang.AnnotationUtils;
import cn.tang.tframe.common.utils.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Set;

/**
 * @author huaicheng.thc
 */
public class WrapAspectUtil {
	public static Object doWrapLogException(ProceedingJoinPoint pjp, String keyword, Logger log) throws Throwable {
		long time = System.currentTimeMillis();
		Object[] args = null;
		Method method = null;
		String className = null;
		String methodName = null;
		String argStr = null;
		Object result = null;
		boolean needLog = false;
		try {
			args = pjp.getArgs();
			method = ((MethodSignature) pjp.getSignature()).getMethod();// 拦截的方法
			className = pjp.getTarget().getClass().getSimpleName();// 拦截的类名
			methodName = method.getName();// 拦截的方法名
			SkipLog skipLogAnnotation = AnnotationUtils.findAnnotation(method, SkipLog.class);
			if (null != skipLogAnnotation) {
				return pjp.proceed(args);
			} else {
				skipLogAnnotation = AnnotationUtils.findAnnotation(pjp.getTarget().getClass(), SkipLog.class);
				if (null != skipLogAnnotation) {
					return pjp.proceed(args);
				}
			}
			RecordLog recordLogAnnotation = AnnotationUtils.findAnnotation(method, RecordLog.class);
			if (null == recordLogAnnotation) {
				recordLogAnnotation = AnnotationUtils.findAnnotation(pjp.getTarget().getClass(), RecordLog.class);
				if (null == recordLogAnnotation) {
					return pjp.proceed(args);
				}
			}
			needLog = true;
			argStr = ToStringUtil.reflectionToString(args, 50, 1024);
			log.info("begin {} {} {}: param={}", new Object[] { keyword, className, methodName, argStr });
			result = pjp.proceed(args);
			return result;
		} catch (Exception targetException) {
			log.error("!!!!  {}  {} {} exception: param={}", new Object[] { keyword, className, methodName, argStr,
					targetException });
			WrapException wrapExceptionAnnotation = AnnotationUtils.findAnnotation(method, WrapException.class);
			if(null != wrapExceptionAnnotation){
				String message = targetException.getMessage();
				return BaseResult.fail(StringUtils.isNotBlank(message) ? message : "服务调用错误");
			}
			throw targetException;
		} finally {
			if (needLog) {
				log.info("end {} {} {}: param={}, result={}, times={}ms",
						new Object[] { keyword, className, methodName, argStr, ToStringUtil.reflectionToString(result),
								System.currentTimeMillis() - time });
			}
		}
	}

	/**
	 * 方法 和 类 接口上只要有一个地方配置了注解返回true,否则返回false
	 * @param clazz
	 * @param method
	 * @param annotationClz
	 * @return
	 */
	public static <A extends Annotation>  boolean hasAnnotation(Class clazz,Method method,Class<A> annotationClz){
		A annotation = findAnnotation(clazz, method, annotationClz);
		return null != annotation;
	}
	/**
	 * 方法 和 类 接口上只要有一个地方配置了注解返回true,否则返回false
	 * @param clazz
	 * @param method
	 * @param annotationClz
	 * @return
	 */
	public static <A extends Annotation> A findAnnotation(Class clazz,Method method,Class<A> annotationClz){
		if(null != method){
			A annotation = AnnotationUtils.findAnnotation(method, annotationClz);
			if(null != annotation){
				return annotation;
			}else
			if (null == annotation && clazz != null) {
				annotation = (A) AnnotationUtils.findAnnotation(clazz, annotationClz);
				if (null != annotation) {
					return annotation;
				}
			}
		}
		return null;
	}
	public static BaseResult exceptionToBaseResult(Throwable throwable) {
		if (null != throwable) {
			if (throwable instanceof BaseRtmException) {
				BaseRtmException excep = (BaseRtmException) throwable;
				String message = excep.getMessage();
				return BaseResult.fail(StringUtils.isNotBlank(message) ? message : "服务调用错误");
			} else if (throwable instanceof ConstraintViolationException) {
				ConstraintViolationException excep = (ConstraintViolationException) throwable;
				String message = null;
				Set<ConstraintViolation<?>> constraintViolations = excep.getConstraintViolations();
				if (null != constraintViolations) {
					for (ConstraintViolation cv : constraintViolations) {
						message = cv.getMessage();
						break;
					}
				}
				return BaseResult.fail(StringUtils.isNotBlank(message) ? message : "服务调用错误");
			}
			String message = throwable.getMessage();
			return BaseResult.fail(StringUtils.isNotBlank(message) ? message : "服务调用错误");
		}
		return null;
	}
}